package com.cman777.springc.ratelimiter.rule;

import com.cman777.springc.ratelimiter.collector.target.Target2ValHandler;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author chenzhicong
 * @time 2020/9/18 9:54
 */
@Slf4j
@Getter
@Setter
public class RateRuleSelector {


    private Set<Dimension> dimensions = new HashSet<>();
    private Map<Dimension, Map<String, RateRule>> ruleMap = new HashMap<>();
    private Set<RateRule> rules = new HashSet<>();
    public final static String WILDCARD = "*";
    public RateRuleSelector(RateRuleImporter rateRuleImporter){
        List<RateRule> rateRules = rateRuleImporter.importRule();
        this.dimensions = rateRules.stream().map(r->r.getDimension()).collect(Collectors.toSet());
        this.ruleMap.putAll(rateRules.stream().sorted(Comparator.comparing(r->r.getOrderNum())).collect(Collectors.groupingBy(r -> r.getDimension(), Collectors.toMap(r -> r.getVal(), Function.identity(),(a,b)->a,()->new LinkedHashMap<>()))));
        this.rules = new HashSet<>(rateRules);
    }

    /**
      * 通过维度和该维度下生成的键寻找第一个匹配的规则
      */
    public RateRule selectRule4Val(Dimension dimension, String val) {
        Map<String, RateRule> valRateRuleMap = ruleMap.get(dimension);
        List<String> keys = Arrays.asList(val.split(Target2ValHandler.SEPARATOR));
        String ruleKey = null;
        try {
            ruleKey = valRateRuleMap.keySet().stream().filter(k -> {
                List<String> keysTpl = Arrays.asList(k.split(Target2ValHandler.SEPARATOR));
                for (int i = 0; i < keys.size(); i++) {
                    String key = keys.get(i);
                    String keyTpl = keysTpl.get(i);
                    if (WILDCARD.equals(keyTpl)) {
                        //通配符 该维度下所有个体都需要限流
                        continue;
                    }
                    if (!key.equals(keyTpl)) {
                        //某个具体维度配置的规则标注的值不一样
                        return false;
                    }
                }
                return true;
            }).findFirst().orElse(null);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        if (ruleKey == null) {
            return null;
        } else {
            return valRateRuleMap.get(ruleKey);
        }
    }


}
